// Copyright 2004-2006 Castle Project - http://www.castleproject.org/
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace ElevatorSpeeches.Framework.Tests
{
    using System;

    using Castle.ActiveRecord;
    using Castle.ActiveRecord.Framework;
    using Castle.ActiveRecord.Framework.Config;

    using NUnit.Framework;

    /// <summary>
    /// This is a suggestion of base class that might 
    /// simplify the unit testing for the ActiveRecord
    /// classes.
    /// <para>
    /// Basically you have to create a separate database
    /// for your tests, which is always a good idea:
    /// - production
    /// - development
    /// - test
    /// </para>
    /// <para>
    /// You have to decide if you want to administrate the
    /// schema on the <c>test</c> database or let ActiveRecord
    /// generate them for you during test execution. Check 
    /// <see cref="AbstractModelTestCase.PrepareSchema"/>
    /// </para>
    /// </summary>
    /// <remarks>
    /// Note that this class enables lazy classes and collections
    /// by using a <see cref="SessionScope"/>.
    /// This have side effects. Some of your test must 
    /// invoke <see cref="Flush"/> 
    /// to persist the changes.
    /// </remarks>
    public abstract class AbstractModelTestCase
    {
        protected TransactionScope scope;

        protected TransactionScope TestTransaction;

        protected bool commit = false;

        [TestFixtureSetUp]
        public virtual void FixtureInit()
        {
            InitFramework();                        
        }

        [SetUp]
        public virtual void Init()
        {
            CreateScope();
        }

        [TearDown]
        public virtual void Terminate()
        {
            DisposeScope();
        }

        [TestFixtureTearDown]
        public virtual void TerminateAll()
        {
            
        }

        protected void Flush()
        {
            SessionScope.Current.Flush();
        }

        protected void CreateScope()
        {
            scope = new TransactionScope();
        }

        protected void DisposeScope()
        {
            if (!commit)
            {
                scope.VoteRollBack();
            }
            else
            {
                scope.VoteCommit();

                scope.Flush();
            }
            
            scope.Dispose();
        }
        

        protected virtual void InitFramework()
        {
            // TODO: dear lord, don't do try catch
            try
            {                
                IConfigurationSource source = ActiveRecordSectionHandler.Instance;
                ActiveRecordStarter.Initialize(System.Reflection.Assembly.Load("ElevatorSpeeches.Framework"), source);
            }
            catch (Exception ex)
            {
                Console.Write(ex.InnerException);
            }
        }
    }
}
